package com.catazy.ocrdemo.manager

import android.graphics.Bitmap
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ThreadUtils
import com.googlecode.tesseract.android.TessBaseAPI
import java.io.File

/**
 * 作者: Tao
 * 日期: 2024/3/6
 * 时间: 17:15
 * 描述: OCR管理类
 */
class OcrManager {
    companion object {
        val INSTANCE: OcrManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            OcrManager()
        }

        const val TESS_ENGINE = TessBaseAPI.OEM_LSTM_ONLY
        const val TESS_LANG = "eng"
    }

    // 是否初始化
    private var tessInit = false

    // 是否正在处理
    private var tessProcessing = false;

    // OCR训练模型API
    private var tessBaseAPI: TessBaseAPI? = null

    // 正在进行的任务
    private var task: ThreadUtils.Task<String>? = null

    // 监听器集合
    private val mListeners: MutableList<OcrRecognizeListener> = mutableListOf()

    /**
     * 初始化OCR训练模型
     */
    fun initTess(dataPath: String) {
        if (tessInit && tessBaseAPI != null) {
            LogUtils.e("OCR训练模型已经初始化")
            return
        }
        try {
            tessBaseAPI = TessBaseAPI(tessProgressListener)
            tessBaseAPI?.let {
                tessInit = it.init(dataPath, TESS_LANG, TESS_ENGINE)
                LogUtils.i("初始化OCR训练模型成功")
            }
        } catch (e: Exception) {
            LogUtils.e("初始化OCR训练模型失败: ${e.message}")
            tessInit = false
        }
    }

    /**
     * 停止OCR识别
     */
    fun stopTess() {
        if (task != null && !task!!.isDone) {
            task!!.cancel()
        }
        // 停止或回收
        if (tessProcessing) {
            tessBaseAPI?.stop()
        } else {
            //没有正在进行的处理，我们必须在这里回收
            tessBaseAPI?.recycle()
        }
        tessProcessing = false
    }

    fun addListener(listener: OcrRecognizeListener) {
        if (mListeners.contains(listener)) {
            return
        }
        mListeners.add(listener)
    }

    fun removeListener(listener: OcrRecognizeListener) {
        mListeners.remove(listener)
    }

    /**
     * 处理图片
     */
    fun recognizeImage(image: Bitmap) {
        if (!tessInit) {
            LogUtils.e("OCR训练模型未初始化")
            return
        }
        if (tessProcessing) {
            LogUtils.e("OCR正在处理中")
            return
        }
        tessProcessing = true

        task = object : ThreadUtils.SimpleTask<String>() {
            override fun doInBackground(): String? {
                LogUtils.i("开始识别图片")
                mListeners.forEach {
                    it.onStart()
                }
                tessBaseAPI?.setImage(image)
                // 使用 getHOCRText（0） 方法触发识别，并发送进度通知和取消正在进行的处理
                tessBaseAPI?.getHOCRText(0)
                return tessBaseAPI?.utF8Text
            }

            override fun onSuccess(result: String?) {
                LogUtils.i("OCR识别结果: $result")
                mListeners.forEach {
                    it.onSuccess(result)
                }
                tessProcessing = false
                //如果我们不再需要识别结果和任何存储的图像数据，我们可以释放它们
                tessBaseAPI?.clear()
            }

            override fun onFail(t: Throwable) {
                LogUtils.e("OCR识别失败: ${t.message}")
                mListeners.forEach {
                    it.onFail(t)
                }
                tessProcessing = false
                //如果我们不再需要识别结果和任何存储的图像数据，我们可以释放它们
                tessBaseAPI?.clear()
            }
        }
        //cpu密集型线程池处理任务
        ThreadUtils.executeByCpu(task)

    }

    private val tessProgressListener =
        TessBaseAPI.ProgressNotifier { p0 ->
            LogUtils.i("OCR解析进度为: ${p0.percent}%")
            mListeners.forEach {
                it.onProgress(p0)
            }
        }


    /**
     * OCR识别监听器
     */
    interface OcrRecognizeListener {
        /**
         * 开始
         */
        fun onStart()

        /**
         * 成功
         * @param result String? 结果
         */
        fun onSuccess(result: String?)

        /**
         * 失败
         * @param t Throwable 异常
         */
        fun onFail(t: Throwable)

        /**
         * 进度
         * @param p0 进度
         */
        fun onProgress(p0: TessBaseAPI.ProgressValues)
    }
}